﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Xml;
using Common.Utilities;
using Common.Utilities.Dispatcher;
using Workflows.Components.Entities.Relations.InferredAssociations;

namespace Workflows.Components.Entities.StreamCollapse
{
    [Serializable]
    public class StreamingCollapseInstruction:InstructionBase 
    {
        #region props
        private string _IdAttributeName;
        /// <summary></summary>
        public string IdAttributeName
        {
            get
            {
                return this._IdAttributeName;
            }
            set
            {
                this._IdAttributeName = value;
            }
        }

        private string _CollapsedIdAttributeName;
        /// <summary></summary>
        public string CollapsedIdAttributeName
        {
            get
            {
                return this._CollapsedIdAttributeName;
            }
            set
            {
                this._CollapsedIdAttributeName = value;
            }
        }

        private string _PartitionedEntityProviderFilePath;
        /// <summary></summary>
        public string PartitionedEntityProviderFilePath
        {
            get
            {
                return this._PartitionedEntityProviderFilePath;
            }
            set
            {
                this._PartitionedEntityProviderFilePath = value;
            }
        }

        private DataProviderType _DbProvider;
        /// <summary></summary>
        public DataProviderType DbProvider
        {
            get
            {
                return this._DbProvider;
            }
            set
            {
                this._DbProvider = value;
            }
        }

        private string _ConnStr;
        /// <summary></summary>
        public string ConnStr
        {
            get
            {
                return this._ConnStr;
            }
            set
            {
                this._ConnStr = value;
            }
        }

        private string _SelectSql;
        /// <summary></summary>
        public string SelectSql
        {
            get
            {
                return this._SelectSql;
            }
            set
            {
                this._SelectSql = value;
            }
        }

        private List<AttributeMetaData> _AttrMetaDatas;
        /// <summary></summary>
        public List<AttributeMetaData> AttrMetaDatas
        {
            get
            {
                return this._AttrMetaDatas;
            }
            set
            {
                this._AttrMetaDatas = value;
            }
        }

        private string _CollapseCalculatorTypeName;
        /// <summary></summary>
        public string CollapseCalculatorTypeName
        {
            get
            {
                return this._CollapseCalculatorTypeName;
            }
            set
            {
                this._CollapseCalculatorTypeName = value;
            }
        }

        private double _NativeAttributeThreshold;
        /// <summary>
        /// add to overall score when sum of native attr comparison score 
        /// is greater than threshold
        /// </summary>
        public double NativeAttributeThreshold
        {
            get
            {
                return this._NativeAttributeThreshold;
            }
            set
            {
                this._NativeAttributeThreshold = value;
            }
        }

        private double _AssociativeAttributeThreshold;
        /// <summary>
        /// add to overall score when sum of associative attr comparison score 
        /// is greater than threshold
        /// </summary>
        public double AssociativeAttributeThreshold
        {
            get
            {
                return this._AssociativeAttributeThreshold;
            }
            set
            {
                this._AssociativeAttributeThreshold = value;
            }
        }

        private double _LinkageAttributeThreshold;
        /// <summary>retrieve linkage distance that are stored in db</summary>
        public double LinkageAttributeThreshold
        {
            get
            {
                return this._LinkageAttributeThreshold;
            }
            set
            {
                this._LinkageAttributeThreshold = value;
            }
        }

        private double _CollapseScoreThreshold;
        /// <summary></summary>
        public double CollapseScoreThreshold
        {
            get
            {
                return this._CollapseScoreThreshold;
            }
            set
            {
                this._CollapseScoreThreshold = value;
            }
        }

        private string _CollapseResultFilePath;
        /// <summary></summary>
        public string CollapseResultFilePath
        {
            get
            {
                return this._CollapseResultFilePath;
            }
            set
            {
                this._CollapseResultFilePath = value;
            }
        }

        private string _TgtConnStr;
        /// <summary></summary>
        public string TgtConnStr
        {
            get
            {
                return this._TgtConnStr;
            }
            set
            {
                this._TgtConnStr = value;
            }
        }

        private string _CollapseInstanceTable;
        /// <summary></summary>
        public string CollapseInstanceTable
        {
            get
            {
                return this._CollapseInstanceTable;
            }
            set
            {
                this._CollapseInstanceTable = value;
            }
        }

        private string _CollapseMappingTable;
        /// <summary></summary>
        public string CollapseMappingTable
        {
            get
            {
                return this._CollapseMappingTable;
            }
            set
            {
                this._CollapseMappingTable = value;
            }
        }

        private Dictionary<string,string> _CollapseInstanceFieldMappings;
        /// <summary></summary>
        public Dictionary<string,string> CollapseInstanceFieldMappings
        {
            get
            {
                return this._CollapseInstanceFieldMappings;
            }
            set
            {
                this._CollapseInstanceFieldMappings = value;
            }
        }

        private string _CollapseMappingEntityIDField;
        /// <summary></summary>
        public string CollapseMappingEntityIDField
        {
            get
            {
                return this._CollapseMappingEntityIDField;
            }
            set
            {
                this._CollapseMappingEntityIDField = value;
            }
        }

        private string _CollapseMappingCollapseIDField;
        /// <summary></summary>
        public string CollapseMappingCollapseIDField
        {
            get
            {
                return this._CollapseMappingCollapseIDField;
            }
            set
            {
                this._CollapseMappingCollapseIDField = value;
            }
        }

        private string _CollapseMappingScoreField;
        /// <summary></summary>
        public string CollapseMappingScoreField
        {
            get
            {
                return this._CollapseMappingScoreField;
            }
            set
            {
                this._CollapseMappingScoreField = value;
            }
        }

        private string _CollapseMappingTraceField;
        /// <summary></summary>
        public string CollapseMappingTraceField
        {
            get
            {
                return this._CollapseMappingTraceField;
            }
            set
            {
                this._CollapseMappingTraceField = value;
            }
        }

        private Dictionary<string,string> _MappingTableFieldMappings;
        /// <summary></summary>
        public Dictionary<string,string> MappingTableFieldMappings
        {
            get
            {
                return this._MappingTableFieldMappings;
            }
            set
            {
                this._MappingTableFieldMappings = value;
            }
        }

        private Dictionary<string,EntityPartitionAttribute> _PartitionAttributes;
        /// <summary></summary>
        public Dictionary<string,EntityPartitionAttribute> PartitionAttributes
        {
            get
            {
                return this._PartitionAttributes;
            }
            set
            {
                this._PartitionAttributes = value;
            }
        }

        private List<List<string>> _MergeableAttributeNames;
        /// <summary></summary>
        public List<List<string>> MergeableAttributeNames
        {
            get
            {
                return this._MergeableAttributeNames;
            }
            set
            {
                this._MergeableAttributeNames = value;
            }
        }
        #endregion

        #region ctor
        public StreamingCollapseInstruction():base(Guid.Empty,Guid.Empty)
        {
            this._IdAttributeName = string.Empty;
            this._CollapsedIdAttributeName = string.Empty;
            this._PartitionedEntityProviderFilePath = string.Empty;
            this._DbProvider = DataProviderType.MSSQL;
            this._ConnStr = string.Empty;
            this._SelectSql = string.Empty;
            this._AttrMetaDatas = new List<AttributeMetaData>();
            this._CollapseCalculatorTypeName = string.Empty;
            this._NativeAttributeThreshold = 0.35;
            this._AssociativeAttributeThreshold = 0.5;
            this._LinkageAttributeThreshold = 0.5;
            this._CollapseScoreThreshold = 0.75;

            this._CollapseResultFilePath = string.Empty;
            this._TgtConnStr = string.Empty;
            this._CollapseInstanceTable = string.Empty;
            this._CollapseInstanceFieldMappings = new Dictionary<string, string>();
            this._CollapseMappingTable = string.Empty;
            this._CollapseMappingEntityIDField = string.Empty;
            this._CollapseMappingCollapseIDField = string.Empty;
            this._CollapseMappingScoreField = string.Empty;
            this._CollapseMappingTraceField = string.Empty;
            this._MappingTableFieldMappings=new Dictionary<string, string>();

            this._PartitionAttributes=new Dictionary<string, EntityPartitionAttribute>();
            this._MergeableAttributeNames=new List<List<string>>();
        }

        public StreamingCollapseInstruction(Guid componentID, Guid jobTicketID,
            string idAttrName, string collapsedIdAttrName, 
            string partitionedEntityProviderFilePath, 
            DataProviderType dbProvider,
            string connStr, string selectSql,
            List<AttributeMetaData> attrMetaDatas, string collapseCalcTypeName,
            double nativeAttrThreshold, double associativeAttrThreshold,
            double linkageAttrThreshold,  double collapseThreshold,  
            string resultFilePath, string tgtConnStr, 
            string collapseInstanceTable, 
            Dictionary<string,string> collapseInstanceFieldMappings,
            string collapseMappingTable,
            string collapseMappingEntityIDField,
            string collapseMappingCollapseIDField,
            string collapseMappingScoreField, 
            string collapseMappingTraceField,
            Dictionary<string,string> mappingTableFieldMappings,
            Dictionary<string,EntityPartitionAttribute> partitionAttrs,
            List<List<string>> mergeableAttrNames)
            : base(componentID, jobTicketID)
        {
            this._IdAttributeName = idAttrName;
            this._CollapsedIdAttributeName = collapsedIdAttrName;
            this._PartitionedEntityProviderFilePath = partitionedEntityProviderFilePath;
            this._DbProvider = dbProvider;
            this._ConnStr = connStr;
            this._SelectSql = selectSql;
            this._AttrMetaDatas = attrMetaDatas;
            this._CollapseCalculatorTypeName = collapseCalcTypeName;
            this._NativeAttributeThreshold = nativeAttrThreshold;
            this._AssociativeAttributeThreshold = associativeAttrThreshold;
            this._LinkageAttributeThreshold = linkageAttrThreshold;
            this._CollapseScoreThreshold = collapseThreshold;

            this._CollapseResultFilePath = resultFilePath;
            this._TgtConnStr = tgtConnStr;
            this._CollapseInstanceTable = collapseInstanceTable;
            this._CollapseInstanceFieldMappings = collapseInstanceFieldMappings;
            this._CollapseMappingTable = collapseMappingTable;
            this._CollapseMappingEntityIDField = collapseMappingEntityIDField;
            this._CollapseMappingCollapseIDField = collapseMappingCollapseIDField;
            this._CollapseMappingScoreField = collapseMappingScoreField;
            this._CollapseMappingTraceField = collapseMappingTraceField;
            this._MappingTableFieldMappings = mappingTableFieldMappings;

            this._PartitionAttributes = partitionAttrs;
            this._MergeableAttributeNames = mergeableAttrNames;
        }

        #endregion

        public override InstructionBase Instantiate(XmlNode xNode)
        {
            if (xNode.Attributes.GetNamedItem("Type").Value == this.GetType().FullName)
            {
                StreamingCollapseInstruction instruction = new StreamingCollapseInstruction();
                instruction.OwnerComponentID = new Guid(xNode.Attributes.GetNamedItem("ComponentID").Value);
                instruction.OwnerWorkerInstanceID = new Guid(xNode.Attributes.GetNamedItem("WorkerID").Value);
                instruction.SubmitTime = DateTime.Parse(xNode.Attributes.GetNamedItem("SubmitTime").Value);
                instruction.StartTime = DateTime.Parse(xNode.Attributes.GetNamedItem("StartTime").Value);

                instruction.IdAttributeName = 
                    XmlDataUtil.GetAttributeValue(xNode, "IdAttributeName", "");
                instruction.CollapsedIdAttributeName = 
                    XmlDataUtil.GetAttributeValue(xNode, "CollapsedIdAttributeName", "");
                instruction.PartitionedEntityProviderFilePath =
                    XmlDataUtil.GetAttributeValue(xNode, "PartitionedEntityProviderFilePath", "");
                instruction.DbProvider =
                    (DataProviderType)
                    int.Parse(
                        XmlDataUtil.GetAttributeValue(
                            xNode, "DbProvider",
                            ((int) DataProviderType.MSSQL).ToString()));
                instruction.ConnStr =
                    XmlDataUtil.GetAttributeValue(xNode, "ConnStr", "");
                instruction.SelectSql =
                    XmlDataUtil.GetAttributeValue(xNode, "SelectSql", "");

                XmlNodeList attrNodes = xNode.SelectNodes("Attributes/Attribute");
                if (attrNodes != null && attrNodes.Count > 0)
                {
                    instruction.AttrMetaDatas = new List<AttributeMetaData>();
                    foreach (XmlNode attrNode in attrNodes)
                    {
                        string assemblyName = XmlDataUtil.GetAttributeValue(attrNode, "AssemblyName", "");
                        string typeNmae = XmlDataUtil.GetAttributeValue(attrNode, "TypeName", "");
                        AttributeType attrType =
                            (AttributeType)
                            int.Parse(XmlDataUtil.GetAttributeValue(attrNode, "AttributeType",
                                                                    ((int)AttributeType.NativeAttribute).ToString()));
                        double posW = double.Parse(XmlDataUtil.GetAttributeValue(attrNode, "PositiveWeight", "1.0"));
                        double negW = double.Parse(XmlDataUtil.GetAttributeValue(attrNode, "NegativeWeight", "-1.0"));
                        bool isExternalAttr =
                            bool.Parse(XmlDataUtil.GetAttributeValue(attrNode, "IsExternal", false.ToString()));
                        DataProviderType extDbProvider =
                            (DataProviderType)
                            int.Parse(
                                XmlDataUtil.GetAttributeValue(
                                    attrNode, "ExtDbProvider", ((int) DataProviderType.MSSQL).ToString()));
                        string extConnStr = XmlDataUtil.GetAttributeValue(attrNode, "ExtConnStr", "");
                        string extSql = XmlDataUtil.GetAttributeValue(attrNode, "ExtSql", "");
                        
                        Dictionary<string,string> comparerSettings=new Dictionary<string, string>();
                        XmlNodeList settingNodes = attrNode.SelectNodes("Setting");
                        if(settingNodes !=null && settingNodes.Count>0)
                        {
                            foreach(XmlNode settingNode in settingNodes)
                            {
                                string name = XmlDataUtil.GetAttributeValue(settingNode, "Name", "");
                                string value = XmlDataUtil.GetAttributeValue(settingNode, "Value", "");
                                comparerSettings.Add(name,value);
                            }
                        }

                        if (attrType == AttributeType.CompositeAttribute)
                        {
                            Dictionary<string, string> argAttrBindings = new Dictionary<string, string>();
                            XmlNodeList attrNameNodes = attrNode.SelectNodes("Attribute");
                            foreach (XmlNode attrNameNode in attrNameNodes)
                            {
                                string argName = XmlDataUtil.GetAttributeValue(attrNameNode, "ArgumentName", "");
                                string attrName = XmlDataUtil.GetAttributeValue(attrNameNode, "AttributeName", "");
                                argAttrBindings.Add(argName, attrName);
                            }
                            
                            AttributeMetaData attrMetaData = new AttributeMetaData(
                                argAttrBindings, assemblyName, typeNmae, 
                                comparerSettings, posW, negW,
                                isExternalAttr, extDbProvider, extConnStr, extSql);
                            instruction.AttrMetaDatas.Add(attrMetaData);
                        }
                        else
                        {
                            string attrName = XmlDataUtil.GetAttributeValue(attrNode, "AttributeName", "");
                            AttributeMetaData attrMetaData = new AttributeMetaData(
                                attrName, attrType, assemblyName, typeNmae, 
                                comparerSettings, posW, negW,
                                isExternalAttr, extDbProvider, extConnStr, extSql);
                            instruction.AttrMetaDatas.Add(attrMetaData);
                        }
                    }
                }
                

                instruction.CollapseCalculatorTypeName = 
                    XmlDataUtil.GetAttributeValue(xNode, "CollapseCalculatorTypeName", "");

                instruction.NativeAttributeThreshold =
                    double.Parse(XmlDataUtil.GetAttributeValue(xNode, "NativeAttributeThreshold", "0.35"));
                instruction.AssociativeAttributeThreshold =
                    double.Parse(XmlDataUtil.GetAttributeValue(xNode, "AssociativeAttributeThreshold", "0.5"));
                instruction.LinkageAttributeThreshold =
                    double.Parse(XmlDataUtil.GetAttributeValue(xNode, "LinkageAttributeThreshold", "0.5"));
                instruction.CollapseScoreThreshold =
                    double.Parse(XmlDataUtil.GetAttributeValue(xNode, "CollapseScoreThreshold", "0.75"));
                
                instruction.CollapseResultFilePath =
                    XmlDataUtil.GetAttributeValue(xNode, "CollapseResultFilePath", "");
                instruction.TgtConnStr =
                    XmlDataUtil.GetAttributeValue(xNode, "TgtConnStr", "");
                instruction.CollapseInstanceTable =
                    XmlDataUtil.GetAttributeValue(xNode, "CollapseInstanceTable", "");
                XmlNodeList tgtTableFieldMappingNodes = xNode.SelectNodes("TgtFieldMappings/TgtFieldMapping");
                if(tgtTableFieldMappingNodes !=null && tgtTableFieldMappingNodes.Count>0)
                {
                    instruction.CollapseInstanceFieldMappings = new Dictionary<string, string>();
                    foreach(XmlNode fieldMappingNode in tgtTableFieldMappingNodes)
                    {
                        string srcField = XmlDataUtil.GetAttributeValue(fieldMappingNode, "SrcField", "");
                        string tgtField = XmlDataUtil.GetAttributeValue(fieldMappingNode, "TgtField", "");
                        instruction.CollapseInstanceFieldMappings.Add(srcField, tgtField);
                    }
                }
                instruction.CollapseMappingTable =
                    XmlDataUtil.GetAttributeValue(xNode, "CollapseMappingTable", "");
                instruction.CollapseMappingEntityIDField =
                    XmlDataUtil.GetAttributeValue(xNode, "CollapseMappingEntityIDField", "");
                instruction.CollapseMappingCollapseIDField =
                    XmlDataUtil.GetAttributeValue(xNode, "CollapseMappingCollapseIDField", "");
                instruction.CollapseMappingScoreField =
                    XmlDataUtil.GetAttributeValue(xNode, "CollapseMappingScoreField", "");
                instruction.CollapseMappingTraceField =
                    XmlDataUtil.GetAttributeValue(xNode, "CollapseMappingTraceField", "");

                XmlNodeList mappingTblFieldMappingNodes = xNode.SelectNodes("MappingTableFieldMappings/FieldMapping");
                if(mappingTblFieldMappingNodes !=null && mappingTblFieldMappingNodes.Count>0)
                {
                    instruction.MappingTableFieldMappings=new Dictionary<string, string>();
                    foreach (XmlNode mappingNode in mappingTblFieldMappingNodes)
                    {
                        string srcField = XmlDataUtil.GetAttributeValue(mappingNode, "SrcField", "");
                        string tgtField = XmlDataUtil.GetAttributeValue(mappingNode, "TgtField", "");
                        instruction.MappingTableFieldMappings.Add(srcField,tgtField);
                    }
                }

                XmlNodeList partitionNodes = xNode.SelectNodes("Partitions/Partition");
                if(partitionNodes !=null && partitionNodes.Count>0)
                {
                    instruction.PartitionAttributes=new Dictionary<string, EntityPartitionAttribute>();
                    foreach(XmlNode partitionNode in partitionNodes)
                    {
                        string attrName = XmlDataUtil.GetAttributeValue(partitionNode, "AttributeName", "");
                        bool isExternal =
                            bool.Parse(XmlDataUtil.GetAttributeValue(partitionNode, "IsExternal", false.ToString()));
                        string entityIDField = XmlDataUtil.GetAttributeValue(partitionNode, "EntityIDField", "");
                        DataProviderType partitionDbProvider =
                            (DataProviderType)
                            int.Parse(XmlDataUtil.GetAttributeValue(partitionNode, "DbProvider", "0"));
                        string partitionConnStr = XmlDataUtil.GetAttributeValue(partitionNode, "ConnStr", "");
                        string partitionSql = XmlDataUtil.GetAttributeValue(partitionNode, "SelectSql", "");
                        SqlDbType dbType =
                            (SqlDbType)
                            int.Parse(XmlDataUtil.GetAttributeValue(partitionNode, "DbType",
                                                                    ((int) SqlDbType.Int).ToString()));
                        
                        EntityPartitionAttribute partitionAtt = new EntityPartitionAttribute(
                            isExternal,attrName, partitionDbProvider,partitionConnStr, 
                            partitionSql, entityIDField, dbType);
                        instruction.PartitionAttributes.Add(attrName, partitionAtt);
                    }
                }

                XmlNodeList mergeAttrNodes = xNode.SelectNodes("MergeableAttributes/MergeableAttribute");
                if(mergeAttrNodes !=null && mergeAttrNodes.Count>0)
                {
                    instruction.MergeableAttributeNames=new List<List<string>>();
                    foreach(XmlNode mergeNode in mergeAttrNodes)
                    {
                        List<string> attrNames=new List<string>();
                        foreach(XmlNode attrNode in mergeNode.ChildNodes)
                        {
                            attrNames.Add(XmlDataUtil.GetAttributeValue(attrNode, "AttributeName", ""));
                        }
                        instruction.MergeableAttributeNames.Add(attrNames);
                    }
                }

                return instruction;
            }
            else
            {
                throw new Exception("Unable to instantiate instruction: invalid type specified in xml node");
            }
        }

        public override XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode)
        {
            XmlNode xNode = XmlDataUtil.AddElement(ref xDoc, parentNode, "Instruction");
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Type", this.GetType().FullName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ComponentID", this.OwnerComponentID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "WorkerID", this.OwnerWorkerInstanceID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SubmitTime", this.SubmitTime.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "StartTime", this.StartTime.ToString());

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "IdAttributeName", this.IdAttributeName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "CollapsedIdAttributeName",this.CollapsedIdAttributeName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "CollapseCalculatorTypeName", this.CollapseCalculatorTypeName);

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "PartitionedEntityProviderFilePath", this.PartitionedEntityProviderFilePath);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "DbProvider", ((int) this.DbProvider).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ConnStr", this.ConnStr);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SelectSql", this.SelectSql);

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode,"NativeAttributeThreshold",this.NativeAttributeThreshold.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode,"AssociativeAttributeThreshold",this.AssociativeAttributeThreshold.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "LinkageAttributeThreshold", this.LinkageAttributeThreshold.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode,"CollapseScoreThreshold",this.CollapseScoreThreshold.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "CollapseCalculatorTypeName", this.CollapseCalculatorTypeName);
            
            // attributes
            if(this.AttrMetaDatas !=null && this.AttrMetaDatas.Count>0)
            {
                XmlNode attrRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "Attributes");
                foreach (AttributeMetaData attributeMetaData in this.AttrMetaDatas)
                {
                    XmlNode attrNode = XmlDataUtil.AddElement(ref xDoc, attrRootNode, "Attribute");
                    XmlDataUtil.UpdateAttribute(ref xDoc, attrNode, "AssemblyName", attributeMetaData.ComparerAssemblyName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, attrNode, "TypeName", attributeMetaData.ComparerTypeName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, attrNode, "AttributeType",
                                                ((int)attributeMetaData.AttributeType).ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, attrNode, "PositiveWeight", attributeMetaData.PositiveMatchWeight.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, attrNode, "NegativeWeight", attributeMetaData.NegativeMatchWeight.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, attrNode, "IsExternal", attributeMetaData.IsExternalAttribute.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, attrNode, "ExtDbProvider", ((int)attributeMetaData.ExternalAttributeDbProvider).ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, attrNode, "ExtConnStr", attributeMetaData.ExternalAttributeConnStr);
                    XmlDataUtil.UpdateAttribute(ref xDoc, attrNode, "ExtSql", attributeMetaData.ExternalAttributeSelectSql);

                    if(attributeMetaData.ComparerSettings !=null && attributeMetaData.ComparerSettings.Count>0)
                    {
                        foreach(string name in attributeMetaData.ComparerSettings.Keys)
                        {
                            XmlNode settingNode = XmlDataUtil.AddElement(ref xDoc, attrNode, "Setting");
                            XmlDataUtil.UpdateAttribute(ref xDoc, settingNode, "Name",name);
                            XmlDataUtil.UpdateAttribute(ref xDoc, settingNode, "Value", attributeMetaData.ComparerSettings[name]);
                        }
                    }

                    if (attributeMetaData.AttributeType == AttributeType.CompositeAttribute)
                    {
                        foreach (string argName in attributeMetaData.ArgNameAttrNameBindings.Keys)
                        {
                            XmlNode attrNameNode = XmlDataUtil.AddElement(ref xDoc, attrNode, "Attribute");
                            XmlDataUtil.UpdateAttribute(ref xDoc, attrNameNode, "ArgumentName", argName);
                            XmlDataUtil.UpdateAttribute(ref xDoc, attrNameNode, "AttributeName",
                                                        attributeMetaData.ArgNameAttrNameBindings[argName]);
                        }
                    }
                    else
                    {
                        XmlDataUtil.UpdateAttribute(ref xDoc, attrNode, "AttributeName", attributeMetaData.AttributeName);
                    }
                }
            }

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "CollapseResultFilePath", this.CollapseResultFilePath);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TgtConnStr", this.TgtConnStr);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "CollapseInstanceTable", this.CollapseInstanceTable);
            if(this.CollapseInstanceFieldMappings!=null && this.CollapseInstanceFieldMappings.Count>0)
            {
                XmlNode fieldMapRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "TgtFieldMappings");
                foreach(string srcField in this.CollapseInstanceFieldMappings.Keys)
                {
                    XmlNode fieldMapNode = XmlDataUtil.AddElement(ref xDoc, fieldMapRootNode, "TgtFieldMapping");
                    XmlDataUtil.UpdateAttribute(ref xDoc, fieldMapNode, "SrcField", srcField);
                    XmlDataUtil.UpdateAttribute(ref xDoc, fieldMapNode, "TgtField", this.CollapseInstanceFieldMappings[srcField]);
                }
            }
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "CollapseMappingTable", this.CollapseMappingTable);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "CollapseMappingEntityIDField",
                                        this.CollapseMappingEntityIDField);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "CollapseMappingCollapseIDField",
                                        this.CollapseMappingCollapseIDField);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "CollapseMappingScoreField", this.CollapseMappingScoreField);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "CollapseMappingTraceField", this.CollapseMappingTraceField);

            if(this.MappingTableFieldMappings !=null && this.MappingTableFieldMappings.Count>0)
            {
                XmlNode mappingTblFieldMappingRootNode = XmlDataUtil.AddElement(ref xDoc, xNode,
                                                                                "MappingTableFieldMappings");
                foreach(string srcField in this.MappingTableFieldMappings.Keys)
                {
                    XmlNode mappingNode = XmlDataUtil.AddElement(ref xDoc, mappingTblFieldMappingRootNode,
                                                                 "FieldMapping");
                    XmlDataUtil.UpdateAttribute(ref xDoc, mappingNode,"SrcField",srcField);
                    XmlDataUtil.UpdateAttribute(ref xDoc, mappingNode,"TgtField",this.MappingTableFieldMappings[srcField]);
                }
            }

            if (this.PartitionAttributes != null && this.PartitionAttributes.Count > 0)
            {
                XmlNode partitionRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "Partitions");
                foreach(EntityPartitionAttribute partitionAttr in this.PartitionAttributes.Values)
                {
                    XmlNode partitionNode = XmlDataUtil.AddElement(ref xDoc, partitionRootNode, "Partition");
                    XmlDataUtil.UpdateAttribute(ref xDoc, partitionNode, "AttributeName",partitionAttr.PartitionAttributeName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, partitionNode, "IsExternal",partitionAttr.IsExternal.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, partitionNode, "DbProvider",((int)partitionAttr.DbProvider).ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, partitionNode, "ConnStr",partitionAttr.ConnStr);
                    XmlDataUtil.UpdateAttribute(ref xDoc, partitionNode, "SelectSql", partitionAttr.SelectSql);
                    XmlDataUtil.UpdateAttribute(ref xDoc, partitionNode, "EntityIDField",
                                                partitionAttr.EntityIDFieldName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, partitionNode, "DbType", ((int)partitionAttr.PartitionAttributeDbType).ToString());
                }
            }

            if(this.MergeableAttributeNames !=null && this.MergeableAttributeNames.Count>0)
            {
                XmlNode mergeRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "MergeableAttributes");
                for(int i=0;i<this.MergeableAttributeNames.Count;i++)
                {
                    XmlNode mergeNode = XmlDataUtil.AddElement(ref xDoc, mergeRootNode, "MergeableAttribute");
                    List<string> attrNames = this.MergeableAttributeNames[i];
                    foreach(string attrName in attrNames)
                    {
                        XmlNode attrNode = XmlDataUtil.AddElement(ref xDoc, mergeNode, "Attribute");
                        XmlDataUtil.UpdateAttribute(ref xDoc, attrNode, "AttributeName", attrName);
                    }
                }
            }

            return xNode;
        }
    }
}
